module(...,package.seeall)
local slen,smatch,sfind,ssub,slower = string.len,string.match,string.find,string.sub,string.lower

--tag: "feed" "ap"

local uartid,uartags,uartopn = 1,{}
local uartcmd = {}
local firstap,wifiopn = {}
local processing

local function openuart(tag)
	uartags[tag] = true
	if not uartopn then
		pm.wake("wifiuart")
		uart.setup(uartid,115200,8,uart.PAR_NONE,uart.STOP_1,0)
		uartopn = true		
		print("wifi.openuart")
	end
end

local function closeuart2()
	uart.close(uartid)
	uartopn = false
	print("wifi.processing1",false)
	processing = false
	pm.sleep("wifiuart")
	print("wifi.closeuart")
end

local function closeuart(tag)
	--print("wifi.closeuart",uartopn,tag)
	if uartopn then
		uartags[tag] = false
		processing = false
		print("wifi.processing2",false)
		for k,v in pairs(uartags) do
			--print("wifi.uartags",k,v)
			if v then				
				exeat()
				return
			end
		end
		write("AT+AMSLEEP=2,180")
		sys.timer_start(closeuart2,50)
		wifiopn = false
	end
end

local function sleep(tag)
	if tag == "feed" then sys.timer_stop(sleep,tag) end
	closeuart(tag)
end

function exeat()
	print("wifi.processing3",processing)
	if processing then return end
	local flg
	for k,v in pairs(uartcmd) do
		if v then
			write(k=="ap" and "AT+CWLAP" or "AT+IPR?")
			flg = true
			uartcmd[k] = false
			break
		end
	end
	if flg then sys.timer_start(wake,150000,"feed") end
end

local function reset3()
	wifiopn = true
	exeat()
end

local function reset2()
	pins.set(false,pins.WIFI_RST)
	sys.timer_start(reset3,1000)
end

function wake(tag,ignorpwr)
	if tag == "feed" then sys.timer_start(sleep,10000,tag) end
	sys.timer_stop(closeuart2)
	openuart(tag)
	uartcmd[tag] = true
	if not wifiopn and not ignorpwr then
		if not sys.timer_is_active(reset2) and not sys.timer_is_active(reset3) then
			pins.set(true,pins.WIFI_RST)
			sys.timer_start(reset2,100)
		end		
	else
		exeat()
	end	
end


local tlist,rspstr,cwlap = {},"",{}

local function delitem(para)
	local i
	for i=1,#tlist do
		if tlist[i].flag and tlist[i].para.cause == para.cause then
			tlist[i].flag = false
			break
		end
	end
end

local function additem(para)
	delitem(para)
	local item,i,fnd = {flag = true, para = para}
	item.para.remain = para.val
	for i=1,#tlist do
		if not tlist[i].flag then
			tlist[i] = item
			fnd = true
			break
		end
	end
	if not fnd then table.insert(tlist,item) end
end

local function isexisttimeritem()
	local i
	for i=1,#tlist do
		if tlist[i].flag then return true end
	end
end

local function timerfunc()
	local i
	for i=1,#tlist do
		--print("wifi.timerfunc@"..i,tlist[i].flag,tlist[i].para.cause,tlist[i].para.val,tlist[i].para.remain,tlist[i].para.cb)
		if tlist[i].flag then
			local rmn,cb = tlist[i].para.remain,tlist[i].para.cb
			if rmn and rmn > 0 then
				tlist[i].para.remain = rmn - 1
			end			
			if tlist[i].para.remain	== 0 then
				if cb then cb({}) end
				clsforap(tlist[i].para)
			end				
		end
	end
	if not isexisttimeritem() then sys.timer_stop(timerfunc) end
end

function clsforap(para)
	assert((para and _G.type(para) == "table" and para.cause),"wifi.clsforap para invalid")
	print("wifi.ctl clsforap",para.cause,para.val,para.cb)
	delitem(para)
	local valid,i
	for i=1,#tlist do
		if tlist[i].flag then
			valid = true
		end		
	end
	if not valid then sleep("ap") end
end

function opnforap(para,ignorpwr)
	assert((para and _G.type(para) == "table" and para.cause),"wifi.opnforap para invalid")
	print("wifi.ctl opnforap",para.cause,para.val,para.cb)
	if not uartags["ap"] then wake("ap",ignorpwr) end
	additem(para)	
	if isexisttimeritem() and not sys.timer_is_active(timerfunc) then
		sys.timer_loop_start(timerfunc,1000)
	end
end

function isactive(para)
	local i
	for i=1,#tlist do
		if tlist[i].flag and tlist[i].para.cause == para.cause then
			return true
		end
	end
end

local function apfnc()
	local i
	for i=1,#tlist do
		if tlist[i].flag then
			if tlist[i].para.cb then tlist[i].para.cb(cwlap) end
			clsforap(tlist[i].para)			
		end			
	end
	cwlap = {}
end

local function parse(data)
	if not data then return end
	--print("wifi.parse",smatch(data,"%+IPR"),data)
	if smatch(data,"%+CWLAP") then
		local d1,d2,ssid,rssi,mac = sfind(data,"%+CWLAP:%s*%(%d,\"([^%c]+)\",([%-]%d+),\"(%w%w:%w%w:%w%w:%w%w:%w%w:%w%w)\",%d+%)")
		if d1 and d2 then
			local id,fnd
			for id=1,#cwlap do
				if cwlap[id].mac == slower(mac) then
					cwlap[id] = {ssid=ssid,rssi=rssi,mac=slower(mac)}
					fnd = true
					break
				end
			end
			if not fnd then cwlap[#cwlap+1] = {ssid=ssid,rssi=rssi,mac=slower(mac)} end
			sys.timer_start(apfnc,1000)
			return true,ssub(data,d2+1,-1)
		end
	elseif smatch(data,"%+IPR") then
		local d1,d2 = sfind(data,"%+IPR:%s*%d+")
		--print("IPR",d1,d2)
		if d1 and d2 then
			sleep("feed")
			return true,ssub(data,d2+1,-1)
		end
	elseif smatch(data,"%+AMSLEEP") then
		local d1,d2 = sfind(data,"%+AMSLEEP")
		if d1 and d2 then
			sys.timer_stop(closeuart2)
			closeuart2()
			return true,ssub(data,d2+1,-1)
		end
	elseif smatch(data,"ready") then		
		local d1,d2 = sfind(data,"ready")
		if d1 and d2 then
			sys.timer_stop(reset3)
			reset3()
			return true,ssub(data,d2+1,-1)
		end
	end

	return false,data
end

local function proc(data)
	if not data or slen(data) == 0 then return end
	rspstr = rspstr..data
	if rspstr ~= "" then
		local result,unproc
		unproc = rspstr
		while true do
			result,unproc = parse(unproc)
			if not unproc or unproc == "" or not result then
				break
			end
		end

		rspstr = unproc or ""
	end
end

local function read()
	local data = ""
	while true do		
		data = uart.read(uartid,"*l",0)
		if slen(data) == 0 then break end
		local b=''
		for i=1,slen(data) do
			b=b .. (ssub(data,i,i)=='\0' and '' or ssub(data,i,i))
		end
		print("wifi.read",b)
		proc(b)
	end
end

function write(cmd)
	print("wifi.write",cmd)
	uart.write(uartid,cmd.."\r")
	print("wifi.processing4",true)
	processing = true
end

local function qryfirstap(dat)
	firstap = dat or {}
end

function getfirstap()
	return firstap
end

function dlock()
	return sys.timer_is_active(wake,"feed",nil,"dlock")
end

sys.reguart(uartid,read)
if rtos.poweron_reason() == rtos.POWERON_KEY or rtos.poweron_reason() == rtos.POWERON_CHARGER then
	sys.timer_start(wake,90000,"feed",nil,"dlock")
	opnforap({cause="FIRSTAP",val=8,cb=qryfirstap},true)
else
	wake("feed")
end
